import os
import cv2 as cv    
import matplotlib.pyplot as plt
import numpy as np  
from matplotlib import rcParams
rcParams['font.sans-serif'] = ['SimHei']  
    
# 读取图片，0表示灰度图像    
img = cv.imread('hanzi1.jpg', 0)    
         
#全局阈值处理
blur = cv.GaussianBlur(img, (5, 5), 0) # 阈值处理的效果受噪声影响较大，常需要先进行滤波等预处理
_, th = cv.threshold(blur, 0, 255, cv.THRESH_BINARY + cv.THRESH_OTSU)
th1_inv = 255 -th

#应用腐蚀操作
kernel1 = np.ones((3,3), np.uint8)
eroded_img = cv.erode(th1_inv, kernel1, iterations=4)

#应用膨胀操作
kernel2 = cv.getStructuringElement(cv.MORPH_CROSS, (4, 4)).astype(np.uint8) 
dilated_img = cv.dilate(eroded_img, kernel2,iterations=8)
median_blurred = cv.medianBlur(dilated_img, 3)#中值滤波去除小白点

#应用闭运算
kernel3 = np.ones((5, 5), np.uint8)
closed_img = cv.morphologyEx(dilated_img, cv.MORPH_CLOSE, kernel3,iterations=25)

#Canney边缘检测
img_blur = cv.GaussianBlur(closed_img,(3,3), 0) #高斯滤波
canny = cv.Canny(img_blur, 100, 200) #Canny边缘检测
contours, hierarchy = cv.findContours(canny, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) # 查找轮廓
cv.drawContours(canny, contours, -1, (255), 2) # 画边界框

#选取汉字轮廓
#轮廓检测
img_copy = th.copy()# 复制图像以绘制边界框
valid_contours_indices = []# 创建一个列表来存储通过周长筛选的轮廓索引
for i, c in enumerate(contours):
    perimeter = cv.arcLength(c, True)
    print("轮廓周长：", perimeter)
    x, y, w, h = cv.boundingRect(c) 
    # 根据周长阈值筛选并绘制边界框
    if perimeter > 350 and perimeter < 600:
        cv.rectangle(img_copy, (x, y), (x + w, y + h), (0, 255, 0), 2)
        valid_contours_indices.append(i)# 将符合条件的轮廓索引添加到列表中
        chars_folder = 'chars'
        if not os.path.exists(chars_folder):
          os.makedirs(chars_folder)
    for i in valid_contours_indices:
    # 获取当前轮廓的边界框坐标
        x, y, w, h = cv.boundingRect(contours[i])
        # 切割图像
        roi = th[y:y+h+15, x:x+w+15]
        # 创建文件保存路径
        filename = os.path.join(chars_folder, f'{i}.jpg')
        # 保存图像
        cv.imwrite(filename, roi)
  
#显示原图灰度图像
plt.figure(figsize=(20, 15))  # 设置更大的图像尺寸
plt.subplot(3, 3, 1)
plt.imshow(img, 'gray')    
plt.title("原图灰度图", fontsize=14)    # 增大字体大小
plt.axis('off') # 隐藏坐标轴    
    
# 显示颠倒后的阈值化图像  
plt.subplot(3,3,2)

plt.imshow(th1_inv, 'gray')    
plt.title("全局阈值处理>>二值化图像", fontsize=14)    
plt.axis('off') # 隐藏坐标轴    
    
# 显示腐蚀后的图像
plt.subplot(3,3,3)
plt.imshow(eroded_img, 'gray')    
plt.title("腐蚀操作>>去除噪点", fontsize=14)    
plt.axis('off') # 隐藏坐标轴    

# 显示膨胀后的图像
plt.subplot(3,3,4)
plt.imshow(median_blurred, 'gray')    
plt.title("膨胀操作>>中值滤波去除小白点", fontsize=14)    
plt.axis('off') # 隐藏坐标轴 

# #显示闭运算后的图像
plt.subplot(3,3,5)
plt.imshow(closed_img, 'gray')    
plt.title("闭运算>>填充闭合区域", fontsize=14)    
plt.axis('off') # 隐藏坐标轴 

# #显示Canney边缘检测
plt.subplot(3,3, 6)
plt.imshow(canny, 'gray')    
plt.title("Canney边缘检测", fontsize=14)    
plt.axis('off') # 隐藏坐标轴 

# #显示汉字轮廓
plt.subplot(3,3, 7)
plt.imshow(img_copy, 'gray')    
plt.title("汉字选中区域", fontsize=14)    
plt.axis('off') # 隐藏坐标轴  
plt.tight_layout(pad=3.0)  # 增加子图之间的间距
plt.show()